﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Services;
using XNAColor = Microsoft.Xna.Framework.Color;
using MainGame.Menu;

namespace MainGame.GamePlay
{
  /// <summary>
  /// Disegna lo stato offerto dal servizio IBoardState e raccoglie e segnala i click
  /// sulle entitá disegnate
  /// </summary>
  public class BoardRenderer : Microsoft.Xna.Framework.DrawableGameComponent, IBoardRenderer
  {
    public class CardState
    {
      public Card card;
      public Vector2 coordPosition;
      public float depth;
      public bool isAnimated;
    }

    private List<CardState> cards;
    public int[] mazzetto = new int[52];
    private bool Animation = false, Input = true;
    public bool Tutorial, Hints;
    public bool Outro = false; // Partita finita
    private GameDifficulty Difficulty;

    public BoardRenderer(Game game)
      : base(game)
    {
      UpdateOrder = (int)ComponentOrders.RENDERER;
      DrawOrder = (int)MenuDepths.GameLayer;

      game.Services.AddService(typeof(IBoardRenderer), this);
    }

    protected override void Dispose(bool disposing)
    {
      Game.Services.RemoveService(typeof(IBoardRenderer));
      base.Dispose(disposing);
    }

    IBoardState board_service;
    public override void Initialize()
    {
      // Servizi
      board_service = Game.Services.GetService(typeof(IBoardState)) as IBoardState;
      var input_services = Game.Services.GetService(typeof(IInputManager)) as IInputManager;
      input_services.OnTap += new InputManager.Tap(input_services_OnTap);
      //input_services.OnDrag += new InputManager.Drag(input_services_Drag);
      //input_services.OnPress += new InputManager.Tap(input_services_Press);
      input_services.OnHorizontalDrag += new InputManager.Drag(input_services_Press);

      // Inizializza Lista delle Carte
      cards = new List<CardState>(52);

      if ((Game.GetContext().currentGame != null) && (Game.GetContext().currentGame.IsValid()))
      {
        // Ripristina valori partita salvata
        mazzetto = Game.GetContext().currentGame.mazzetti;
        tutorialTime = Game.GetContext().currentGame.timeElapsed;
      }
      else
      {
        // Inizializza Elenco dei Mazzetti (Nuova Partita)
        for (int i = 0; i < 52; i++) mazzetto[i] = 1;
      }

      Tutorial = Game.GetContext().currentConfig.tutorial;
      Hints = Game.GetContext().currentConfig.hints;
      Difficulty = Game.GetContext().currentConfig.difficulty;

      base.Initialize();
    }

    /// <summary>
    /// Aggiorna carte in gioco, posizioni, profondità, mazzetti 
    /// </summary>
    public void UpdateCards()
    {
      cards.Clear();

      for (int i = 0; i < board_service.Players.ElementAt(0).Cards.Count; i++)
      {
        var c = board_service.Players.ElementAt(0).Cards.ElementAt(i); // Carta
        int mazz = mazzetto[i];
        if (mazz > 10) mazz = 10;
        var r = new Vector2(15 + i * CARD_WIDTH + (mazz - 1), 100 - (mazz - 1)); // Posizione          
        float dpt = 0.01f / (i + 1); // Profondità

        cards.Add(new CardState() { card = c, coordPosition = r, depth = CARD_DEPTH + dpt, isAnimated = false });
      }

      updt = false;
    }

    SpriteBatch sprite_batch;
    Texture2D White_Texture, Card_Texture, Background_Texture, Exit_Background_Texture;
    Texture2D Arrow_Texture, InfoBox_Texture;
    Texture2D Deck_Texture, Back_Card_Texture;
    XNAColor color_Background = XNAColor.White;
    SpriteFont font1;
    Matrix screen_transform, smaller_screen_transform;
    RenderTarget2D smaller_render_target;

    /// <summary>
    /// LOAD CONTENT
    /// </summary>
    protected override void LoadContent()
    {
      smaller_render_target = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width / 3, GraphicsDevice.Viewport.Height / 3);
      smaller_screen_transform = Matrix.CreateScale((float)smaller_render_target.Width / GraphicsDevice.Viewport.Width,
          (float)smaller_render_target.Height / GraphicsDevice.Viewport.Height, 1.0f);

      var content = Game.Content;

      // FONT
      font1 = content.Load<SpriteFont>("small_font");

      // TEXTURE
      White_Texture = content.Load<Texture2D>("white_pixel");

      // Carta Vuota
      Card_Texture = Game.Content.Load<Texture2D>(@"Images//Game//card");

      // Carte e Dorso
      Deck_Texture = Game.Content.Load<Texture2D>(@"Images//Decks//Deck_" + Game.GetContext().currentConfig.chosenDeck);
      Back_Card_Texture = Game.Content.Load<Texture2D>(@"Images//Decks//Back_" + Game.GetContext().currentConfig.chosenDeck);

      // Background
      Background_Texture = Game.Content.Load<Texture2D>(@"Images//Backgrounds//BG_" + Game.GetContext().currentConfig.chosenBackground);
      Exit_Background_Texture = Game.Content.Load<Texture2D>(@"Images//Menu//SquarePaper");
      

      // Elementi Grafici
      Arrow_Texture = Game.Content.Load<Texture2D>(@"Images//Game//arrow");
      InfoBox_Texture = Game.Content.Load<Texture2D>(@"Images//Game//roundedBox");

      sprite_batch = Game.GetContext().SpriteBatch;
      screen_transform = Game.GetContext().ScreenTransform;

      base.LoadContent();

    }

    /// 
    /// INPUT
    /// 

    Rectangle pack_rect = new Rectangle(20, 330, CARD_WIDTH, CARD_HEIGHT); // Posizione e Dimensione del Mazzo
    Point tap_position, prev_tap_position;
    bool tapping;
    /// <summary>
    /// Gestisce il Tapping
    /// </summary>
    /// <param name="tap_position">Posizione dove è avvenuto il Tap</param>
    void input_services_OnTap(Vector2 tap_position)
    {
      if (this.Enabled == false || Animation || !Input) return;

      prev_tap_position = this.tap_position;
      this.tap_position = tap_position.ToPoint(screen_transform);

      tapping = true;

      // Tap sul Mazzo, estrae nuova carta
      if (pack_rect.Contains(this.tap_position))
      {
        // Deseleziona eventuali carte sul tavolo
        if (!extractCard)
        {
          board_service.Players.ElementAt(0).Cards.ForEach(c => c.Selected = false);
          if (board_service.Pack.Cards.Count() > 0)
            if (Difficulty != GameDifficulty.Hard)
            {
              // Difficoltà Easy e Normal
              color_pack = XNAColor.White;

              extractCard = true;
              scrolling = true; // AGG

              ClickPack(0, 1);
            }
            else
            {
              // Difficoltà Hard
              if (board_service.Players.ElementAt(0).MossePossibili() == 0)
              {
                color_pack = XNAColor.White;

                extractCard = true; 
                scrolling = true; // AGG

                ClickPack(0, 1);
              }
              else
              {
                color_pack = XNAColor.Red;
              }
            }
        }

      }
    }

    Point drag_position;
    Vector2 drag_direction = Vector2.Zero;
    bool drag = false;
    /// <summary>
    /// Gestisce il Drag
    /// </summary>
    /// <param name="press_position"></param>
    void input_services_Drag(Vector2 press_position)
    {
      if (this.Enabled == false || Animation || !Input) return;

      drag = true;

      Point new_drag_position = press_position.ToPoint(screen_transform);

      // Calcola la direzione del drag
      if (this.drag_position.X < new_drag_position.X) drag_direction.X = 1;
      if (this.drag_position.X > new_drag_position.X) drag_direction.X = -1;
      if (this.drag_position.X == new_drag_position.X) drag_direction.X = 0;

      if (this.drag_position.Y < new_drag_position.Y) drag_direction.Y = 1;
      if (this.drag_position.Y > new_drag_position.Y) drag_direction.Y = -1;
      if (this.drag_position.Y == new_drag_position.Y) drag_direction.Y = 0;

      this.drag_position = new_drag_position;
    }

    // Press
    bool press = false;
    private void input_services_Press(Vector2 press_position)
    {
      this.tap_position = press_position.ToPoint(screen_transform);
      press = true;
    }

    /// 
    /// UPDATE
    ///

    bool updt = true;
    bool intro = true;
    int counter = 0, timer = 0;
    public override void Update(GameTime gameTime)
    {

      if (updt) UpdateCards(); // Aggiorna la Lista delle Carte inizialmente

      // INTRO
      if (intro) Intro(gameTime);
      else
        if (Tutorial) tutorialTime += gameTime.dt();

      // Fa scorrere la schermata di gioco
      ScrollingScreen();

      if (Outro) DrawOutro();

      base.Update(gameTime);
    }

    float wait = 0;
    /// <summary>
    /// Disegna Introduzione del Gioco (Animazione Iniziale: Estrazione prime carte )
    /// </summary>
    private void Intro(GameTime gameTime)
    {
      if (counter < 2 && Game.GetContext().currentGame == null)
      {
        Animation = true;
        Hints = false;
        Tutorial = false;
        timer++;
        wait += gameTime.dt();
        if (wait > 1.5f && timer > 15) { counter++; ClickPack(0, 1); extractCard = true; timer = 0; }
      }
      else
      {
        timer++;
        if (timer > 30)
        {
          intro = false;
          Animation = false;
          Tutorial = Game.GetContext().currentConfig.tutorial;
          Hints = Game.GetContext().currentConfig.hints;
        }
      }
    }

    ///
    /// DRAW
    ///

    /// <summary>
    /// Disegna la scena 
    /// </summary>
    /// <param name="gameTime"></param>
    public override void Draw(GameTime gameTime)
    {
      if (Enabled == false)
      {
        GraphicsDevice.SetRenderTarget(smaller_render_target);
        GraphicsDevice.Clear(XNAColor.Black);
        sprite_batch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, null, null, null, null, smaller_screen_transform);
      }
      else
      {
        sprite_batch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, null, null, null, null, screen_transform);
      }

      // Disegna il tavolo da gioco
      DrawBoard();

      // Disegna i mazzetti accumulati sotto le carte in gioco
      DrawMazzetti();

      // Disegna Fila di carte
      DrawPlayerBlock(0);

      // Animazione rimozione di una carta
      RemoveCard();

      // Disegna Tutorial
      if (Tutorial && !intro) DrawTutorial(gameTime);

      sprite_batch.End();

      if (Enabled == false)
      {
        GraphicsDevice.SetRenderTarget(smaller_render_target);
        sprite_batch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, smaller_screen_transform);
      }
      else
      {
        sprite_batch.Begin();
      }

      // Disegna Mazzo
      DrawPack();

      // Visualizza Frecce Direzionali Scrolling
      DrawArrow();

      // Disegna Animazione Carta Estratta dal Mazzo
      DrawExtractCard();

      sprite_batch.End();

      if (Enabled == false)
      {
        GraphicsDevice.SetRenderTarget(null);
        sprite_batch.Begin();
        sprite_batch.Draw(smaller_render_target, new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), XNAColor.White);

        sprite_batch.End();
      }

      base.Draw(gameTime);

      tapping = false;
      drag = false;
      press = false;
    }


    /// <summary>
    /// Disegna il tavolo da gioco "Tavolo Verde"
    /// </summary>
    private void DrawBoard()
    {
      // La lunghezza del tavolo si adatta al numero da carte disposte su di esso
      // In ogni schermata sono visibili n carte, 
      int WIDTH = (cards.Count / 7) + 2;

      for (int i = 0; i < WIDTH; i++)
      {
        /*if (i % 2 == 0)*/
        sprite_batch.Draw(Background_Texture, new Rectangle((800 * i), 0, 800, 480), null, color_Background, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
        //else sprite_batch.Draw(background, new Rectangle((800 * i), 0, 800, 480), null, color_Background, 0.0f, Vector2.Zero, SpriteEffects.FlipHorizontally, 0.0f);
      }

      if (Outro) sprite_batch.Draw(Exit_Background_Texture, new Rectangle(0, 0, 800, 480), null, XNAColor.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
        
    }


    static readonly int CARD_WIDTH = 110;
    static readonly int CARD_HEIGHT = 150;
    float CARD_DEPTH = 0.8f;
    int nextSlot;
    bool isSelectedCard = false;
    Card selectedCard;
    XNAColor ColorSlots = XNAColor.Green;
    int attesaMessaggio1 = 0, yMove = 0;
    /// <summary>
    /// Disegna fila di carte in gioco sul tavolo
    /// </summary>
    /// <param name="player_index">Indice del giocatore</param>
    private void DrawPlayerBlock(int player_index)
    {
      if (cards.Any() == false) return;

      for (int i = 0; i < cards.Count; i++)
      {
        var c = cards[i].card;
        var r = new Rectangle((int)cards[i].coordPosition.X, (int)cards[i].coordPosition.Y, CARD_WIDTH, CARD_HEIGHT);
        var d = cards[i].depth;

        if (c.Selected)
        {
          if (tutorialTime > 15 && tutorialTime < 20) tutorialTime = 20; //Sblocca attesa Tutorial

          // Disegna i 2 Target Slot accanto alla carta selezionata
          if (Hints && r.X > CARD_WIDTH && !Animation)
          {
            if (ColorSlots.A < 255) { ColorSlots.A += 5; }
            else ColorSlots.A = 0;

            if (i < cards.Count - 1)
            {
              sprite_batch.Draw(InfoBox_Texture, new Rectangle((int)cards[i - 1].coordPosition.X - 5, (int)cards[i - 1].coordPosition.Y - 5, CARD_WIDTH + 10, CARD_HEIGHT + 10), null, ColorSlots, 0.0f, Vector2.Zero, SpriteEffects.None, cards[i - 1].depth - 0.001f);
              sprite_batch.Draw(InfoBox_Texture, new Rectangle((int)cards[i + 1].coordPosition.X - 5, (int)cards[i + 1].coordPosition.Y - 5, CARD_WIDTH + 10, CARD_HEIGHT + 10), null, ColorSlots, 0.0f, Vector2.Zero, SpriteEffects.None, cards[i + 1].depth - 0.001f);
            }
          }
          else ColorSlots.A = 0;

          if (tapping)
          {
            // Controlla se la carta precedentemente selezionata si trova a destra o a sinistra di quella attuale
            Rectangle target = new Rectangle(0, 0, 0, 0);
            //int targetIdx = i;
            //if (prev_tap_position.X > tap_position.X)
            //{
            // La carta selezionata in precedenza si trova a destra di quella attuale
            //sx = false;
            //  targetIdx++;
            //}
            //if (prev_tap_position.X < tap_position.X)
            //{
            // La carta selezionata in precedenza si trova a sinistra di quella attuale
            //sx = true;
            //  targetIdx--;
            //}

            //target = new Rectangle((int)cards[targetIdx].coordPosition.X - (CARD_WIDTH + 5), r.Y + 5, CARD_WIDTH - 5, CARD_HEIGHT - 5);
            //target.Offset(position, 0);

            if (i == 0)
            {
              sx = false;
              target = new Rectangle((int)cards[i].coordPosition.X + (CARD_WIDTH + 5), r.Y + 5, CARD_WIDTH - 5, CARD_HEIGHT - 5);
            }
            else
            {
              if (board_service.Players.ElementAt(0).Cards[i - 1].Selected)
              {
                sx = true;
                target = new Rectangle((int)cards[i].coordPosition.X - (CARD_WIDTH + 5), r.Y + 5, CARD_WIDTH - 5, CARD_HEIGHT - 5);
              }
              else
              {
                sx = false;
                target = new Rectangle((int)cards[i].coordPosition.X + (CARD_WIDTH + 5), r.Y + 5, CARD_WIDTH - 5, CARD_HEIGHT - 5);
              }
            }
            //target.Offset(position, 0);

            //Rectangle target = new Rectangle(r.X - (CARD_WIDTH + 5), r.Y + 5, CARD_WIDTH - 5, CARD_HEIGHT - 5);
            //Rectangle target2 = new Rectangle(r.X + CARD_WIDTH + 5, r.Y + 5, CARD_WIDTH - 5, CARD_HEIGHT - 5);
            //target.Offset(position, 0);
            //target2.Offset(position, 0);
            //Point p = new Point(Math.Abs(position - tap_position.X), tap_position.Y);
            Point p = new Point(Math.Abs(position - tap_position.X), tap_position.Y);

            if (target.Contains(p))
              if (ReleasePlayerCard != null)
              {
                //sx = true;
                ReleasePlayerCard(player_index, i, sx); // ReleasePlayerCard(player_index, targetIdx, sx);
                //if (sx)
                //ReleasePlayerCard(player_index, i - 1, sx);
                //else
                //  ReleasePlayerCard(player_index, i + 1, sx);
                isSelectedCard = true;
                if (cards.Count != board_service.Players.ElementAt(0).Cards.Count)
                {
                  // La mossa e' valida: rimuovi una carta
                  remove = true;
                  ind = i; // ind = targetIdx;
                  board_service.Players.ElementAt(0).Cards.ForEach(card => card.Selected = false);
                  //if (sx)
                  //  rempos = cards.ElementAt(targetIdx + 1).coordPosition;
                  //else
                  //  rempos = cards.ElementAt(targetIdx - 1).coordPosition;
                }
                else
                  //board_service.Players.ElementAt(0).Cards[targetIdx].Selected = false;
                  board_service.Players.ElementAt(0).Cards[i].Selected = false;
              }

            //if (target2.Contains(p))
            //  if (ReleasePlayerCard != null)
            //  {
            //    sx = false;
            //    ReleasePlayerCard(player_index, i, sx);
            //    isSelectedCard = true;
            //    index = cards.Count;
            //    if (cards.Count != board_service.Players.ElementAt(0).Cards.Count)
            //    {
            //      remove = true;
            //      ind = i;
            //      rempos = cards.ElementAt(i + 1).coordPosition;
            //    }
            //  }

            //if (targetIdx > 0)
            //{
            //  selectedCard = cards.ElementAt(targetIdx - 1).card;
            //}
            //if (i > 0)
            //{
            //  selectedCard = cards.ElementAt(i - 1).card;
            //}
          }

        }


        if (DrawCard(c, r, d) && !remove)
          if (ClickPlayerCard != null)
          {
            scrolling = false;
            yMove = 0;
            attesaMessaggio1 = 0;
            ColorSlots.A = 0;
            ClickPlayerCard(player_index, i);
          }
      }

      // Se sono rimaste due carte selezionate, deselezionale
      if (board_service.Players.ElementAt(0).Cards.Count(c => c.Selected) >= 2)
        board_service.Players.ElementAt(0).Cards.ForEach(c => c.Selected = false);

      // Calcola e Disegna prossimo Slot Libero
      nextSlot = (15 + board_service.Players.ElementAt(0).Cards.Count * CARD_WIDTH);
      if (Hints && !extractCard && board_service.Players.ElementAt(0).MossePossibili() == 0) sprite_batch.Draw(Card_Texture, new Rectangle(nextSlot, 100, CARD_WIDTH, CARD_HEIGHT), null, new XNAColor(100, 100, 100, 50), 0.0f, Vector2.Zero, SpriteEffects.None, 0.5f);
    }


    /// <summary>
    /// Disegna Carta da gioco su tavolo
    /// </summary>
    /// <param name="c">Carta da disegnare</param>
    /// <param name="Card_Rectangle">Rettangolo che drescrive posizione e dimensione della carta</param>
    /// <returns>Restitiusce un bool che indica se la carta appena disegnata è anche Selezionata</returns>
    private bool DrawCard(Card c, Rectangle Card_Rectangle, float Card_depth)
    {
      XNAColor ColorCard = XNAColor.White;

      int seed = 0;
      if (c.Seed == CardSeed.Hearts) { seed = 0; }
      if (c.Seed == CardSeed.Diamonds) { seed = 1; }
      if (c.Seed == CardSeed.Clubs) { seed = 2; }
      if (c.Seed == CardSeed.Spades) { seed = 3; }

      //Ombra
      sprite_batch.Draw(Card_Texture, new Rectangle(Card_Rectangle.X, Card_Rectangle.Y, CARD_WIDTH, CARD_HEIGHT), null, new XNAColor(0, 0, 0, 100), 0.0f, Vector2.Zero, SpriteEffects.None, Card_depth - 0.7f);

      // Disegna carta selezionata sulle altre
      if (c.Selected)
      {
        if (yMove < 15) yMove += 4;

        Card_Rectangle.Y -= yMove;

        Card_depth = CARD_DEPTH + 0.1f;
        ColorCard = XNAColor.Yellow;

        if (Tutorial)
        {
          attesaMessaggio1++;
          int messagePosition = (BOARD_WIDTH / 2) - (int)(font1.MeasureString(Locale.Strings.TutorialHint01).X / 2); //Card_Rectangle.X - CARD_WIDTH / 2;
          int messagePosition2 = messagePosition - 50;

          if (attesaMessaggio1 > 50) DrawMessage(Locale.Strings.TutorialHint01, font1, new Vector2(messagePosition, 50));
          if (attesaMessaggio1 > 60) DrawMessage(Locale.Strings.TutorialHint02.Replace("\\n", "\n"), font1, new Vector2(messagePosition2, 230));
        }

      }

      sprite_batch.Draw(Deck_Texture, Card_Rectangle, new Rectangle((Deck_Texture.Width / 13) * (c.Value - 1), (Deck_Texture.Height / 4) * (seed), Deck_Texture.Width / 13, Deck_Texture.Height / 4), ColorCard, 0.0f, Vector2.Zero, SpriteEffects.None, Card_depth);

      Point pr = new Point(Math.Abs(position - tap_position.X), tap_position.Y);
      return tapping && Card_Rectangle.Contains(pr);
    }

    Point pack_position = new Point(20, 320);
    XNAColor color_pack = XNAColor.White;
    private int color_pack_Alpha = 200, segno = 1, attesaMessaggio = 0;
    /// <summary>
    /// Disegna il mazzo composto da n carte
    /// </summary>
    /// <param name="n">Numero di carte</param>
    private void DrawPack()
    {
      // ANIMAZIONE
      // Se non ci sono mosse possibili il mazzo cambia colore
      if (board_service.Players.ElementAt(0).MossePossibili() == 0)
      {
        color_pack = XNAColor.Yellow;
        if (color_pack_Alpha == 100 || color_pack_Alpha == 250) { segno *= -1; attesaMessaggio++; }
        color_pack_Alpha += (10 * segno);

        if (Enabled == true) color_pack.A = (byte)color_pack_Alpha;

        if (extractCard) attesaMessaggio = 0;

        if (Tutorial && attesaMessaggio > 10)
        {
          DrawMessage(Locale.Strings.TutorialHint03, font1, new Vector2(pack_position.X + 125 + position, pack_position.Y + 100));
        }
      }
      else
      {
        attesaMessaggio = 0;
        color_pack_Alpha = 200;
        color_pack = XNAColor.White;
        if (Difficulty == GameDifficulty.Hard) color_pack = XNAColor.Lerp(XNAColor.Gray, XNAColor.Transparent, 0.3f);
      }

      int n = board_service.Pack.Cards.Count();
      int count = n; // Disegna al più 10 carte

      if (n > 10) count = 10 % n;
      if (n > 0)
        for (int i = 0; i < count; i++)
        {
          // Mazzo: n carte (dorso) sovrapposte e sfasate 
          sprite_batch.Draw(Back_Card_Texture, new Rectangle(pack_position.X + i, pack_position.Y - i, CARD_WIDTH, CARD_HEIGHT), color_pack);
          float depth = (1 / n) * i;
        }

      // Disegna numero di carte del mazzo
      if (n > 0)
      {
        sprite_batch.DrawString(font1, n.ToString(), new Vector2(120, 450), XNAColor.Black, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
        sprite_batch.DrawString(font1, n.ToString(), new Vector2(121, 451), XNAColor.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
      }

      //DrawMessage(MessagePack, font, new Vector2(pack_position.X + 120, pack_position.Y + 30));
    }

    ///
    /// ANIMAZIONI
    ///

    bool extractCard = false;
    int ExtractCardStep = 0, dim = 0;
    float roll = 0.5f;
    Rectangle ExtractCardRectangle = new Rectangle(20, 330, CARD_WIDTH, CARD_HEIGHT);
    /// <summary>
    /// Disegna Animazione Carta estratta dal mazzo
    /// </summary>      
    public void DrawExtractCard()
    {
      if (extractCard)
      {
        XNAColor c = Color.White;

        int Xslot = (int)Math.Abs(position + nextSlot - CARD_WIDTH); // Slot di destinazione
        Vector2 finalPosition = new Vector2(Xslot, 100);

        Vector2 track = finalPosition - new Vector2(pack_position.X, pack_position.Y);
        Vector2 ExtractCardVector = new Vector2(Xslot - ExtractCardRectangle.X, 100 - ExtractCardRectangle.Y);

        int speed = 70;

        // Step 0 - Sposta carta fino alla posizione finale
        if (ExtractCardStep == 0)
        {
          if (ExtractCardRectangle.X < Xslot && ExtractCardRectangle.Y > 100)
          {
            if (ExtractCardRectangle.Y < 150 && ExtractCardRectangle.X > (Xslot - 50))
            {
              speed = 10;
              //dim += 5;
              //roll -= 0.025f;
            } // Ruota carta

            // Applica spostamento
            track.Normalize();
            track *= speed;

            ExtractCardRectangle.X += (int)track.X; // Aumenta Velocità
            ExtractCardRectangle.Y += (int)track.Y;

            //ExtractCardRectangle.Width -= dim; // Gira la Carta

            sprite_batch.Draw(Back_Card_Texture, new Rectangle(ExtractCardRectangle.X + 10, ExtractCardRectangle.Y + 10, CARD_WIDTH, CARD_HEIGHT), null, new XNAColor(0, 0, 0, 100), roll, Vector2.Zero, SpriteEffects.None, 0.8f); // Ombra               
            sprite_batch.Draw(Back_Card_Texture, ExtractCardRectangle, null, c, roll, Vector2.Zero, SpriteEffects.None, 0.9f);          
              
          }
          else ExtractCardStep++; // Passa Step Successivo
        }

        if (ExtractCardStep == 1) // Step 1 - Imposta Coordinate finale 
        {
          ExtractCardRectangle.X = Xslot + (CARD_WIDTH / 2);
          ExtractCardRectangle.Y = 100;
          
          ExtractCardStep++; // Passa Step Successivo
        }

        if (ExtractCardStep == 2) // Step 2 - Ruota-Scopre la carta 
        {
          dim += 15;
          roll -= 0.025f;
          ExtractCardRectangle.Width -= dim; // Gira la Carta

          if (ExtractCardRectangle.Width < 5) ExtractCardStep++; // Passa Step Successivo
          
          sprite_batch.Draw(Back_Card_Texture, new Rectangle(ExtractCardRectangle.X + 10, ExtractCardRectangle.Y + 10, ExtractCardRectangle.Width + 30, CARD_HEIGHT), null, new XNAColor(0, 0, 0, 100), roll, Vector2.Zero, SpriteEffects.None, 0.8f); // Ombra               
          sprite_batch.Draw(Back_Card_Texture, ExtractCardRectangle, null, c, roll, Vector2.Zero, SpriteEffects.None, 0.9f);

        }

        if (ExtractCardStep == 3)
        {
          // Reset valori iniziali
          ExtractCardRectangle.Location = new Point(20, 330);
          ExtractCardRectangle.Width = CARD_WIDTH;
          extractCard = false;
          ExtractCardStep = 0;
          dim = 0;
          roll = 0.5f;
          UpdateCards();
        }
      }     
    }

    int BOARD_WIDTH = 800;
    int position = 0;
    bool scrolling = false;
    /// <summary>
    /// Gestisce lo scrolling del tavolo da gioco
    /// </summary>
    public void ScrollingScreen()
    {
      int scroll_speed = 30;
      int WIDTH = cards.Count / 7;
      if (WIDTH == 0)
      {
        position = 0;
        screen_transform = Matrix.CreateTranslation(new Vector3(position, 0, 0));
        return;
      }
      int tableWidth = -(BOARD_WIDTH * WIDTH) - 100;
      // Position of the slider is:
      // 50 +                         (initial position)
      // ((800 - 100 - 100) *         (bar width = BOARD_WIDTH - slider width - arrows width) 
      // position /                   (current position on the table)
      // tableWidth)                  (width of the table)
      sliderRectangle = new Rectangle(50 + (600 * position / tableWidth), 250, 100, 50);

      // INPUT UTENTE
      if (tapping || press)
      {
        if (tap_position.Y < 350 && tap_position.Y > 250)
        {
          // Frecce direzionali
          if (tap_position.X < 75)
          { position += scroll_speed * 10; scrolling = false; ColorSlider = new XNAColor(200, 200, 200, 100); } // SX
          if (tap_position.X > 725)
          { position -= scroll_speed * 10; scrolling = false; ColorSlider = new XNAColor(200, 200, 200, 100); } // DX

          // Slider
          if ((!pack_rect.Contains(this.tap_position)) && tap_position.X < 725 && tap_position.X > 75)
          {
            ColorSlider = new XNAColor(200, 200, 200, 100);

            var tapToSlider = sliderRectangle.Center.X - tap_position.X;
            if (Math.Abs(tapToSlider) > scroll_speed)
            {
              if (tapping)
                scroll_speed *= 10;
              if (tapToSlider > 0)
              { position += scroll_speed; scrolling = false; } // SX
              if (tapToSlider < 0)
              { position -= scroll_speed; scrolling = false; } // DX
            }
          }
        }
      }
      else
      {
        //ColorSlider = Color.Transparent;
      }

      // Controlli per non uscire fuori dal Tavolo
      if (position <= tableWidth) { position = tableWidth; }
      if (position >= 0) position = 0;

      if (nextSlot < 580 - position) scrolling = false;

      if (scrolling)
      {
        Rectangle bounds = new Rectangle(580 - position, 100, CARD_WIDTH, CARD_HEIGHT);
        Point nextSlotPoint = new Point(nextSlot, 150);

        //// DEBUG
        //sprite_batch.Draw(White_Texture, bounds, Color.AliceBlue);
        //sprite_batch.Draw(White_Texture, new Rectangle(nextSlot, 200, 10, 10), Color.AntiqueWhite);
        //sprite_batch.DrawString(font1, "nCards: " + cards.Count(), new Vector2(300 - position, 300), XNAColor.Black);

        //if (nextSlotPoint.X < bounds.Right) scrolling = false;
          if (nextSlotPoint.X > bounds.Left)
            position -= (10 + (cards.Count / 4));
        //if (!bounds.Contains(nextSlotPoint)) position -= (10 + (cards.Count / 4));
      }

      screen_transform = Matrix.CreateTranslation(new Vector3(position, 0, 0));
    }

    XNAColor ArrowColor = XNAColor.Yellow, ColorSlider = new XNAColor(100, 100, 100, 100);
    int ArrowTime = 0, ArrowDim = 0;
    Rectangle sliderRectangle;
    /// <summary>
    /// Disegna Frecce direzionali per lo Scrolling del Tavolo
    /// </summary>
    private void DrawArrow()
    {
      ArrowTime++;
      ArrowDim++;

      if (ArrowTime < 30)
      {
        if (ArrowDim > 10) ArrowDim = 0;
        ArrowColor = new XNAColor(250, 250, 250, 25 * ArrowDim);
      }
      else
      {
        //ArrowTime = 0;
        ArrowDim = 0;
        ArrowColor = XNAColor.Yellow;
      }

      if (position < 0 && Enabled)
      {
        sprite_batch.Draw(Arrow_Texture, new Rectangle(5 - (ArrowDim / 2), 250 - (ArrowDim / 2), (Arrow_Texture.Width / 2) + ArrowDim, (Arrow_Texture.Height / 2) + ArrowDim), ArrowColor);

      }
      else ArrowTime = 0;

      if (cards.Count() > 6 && Enabled)
      {
        if (position > -((BOARD_WIDTH * (cards.Count / 7)) + 100))
          sprite_batch.Draw(Arrow_Texture, new Rectangle(750 - (ArrowDim / 2), 250 - (ArrowDim / 2), (Arrow_Texture.Width / 2) + ArrowDim, (Arrow_Texture.Height / 2) + ArrowDim), null, ArrowColor, 0.0f, Vector2.Zero, SpriteEffects.FlipHorizontally, 0.5f);

        // Draw barra dello slider
        sprite_batch.Draw(InfoBox_Texture, new Rectangle(-100, 250, 1000, 50), new XNAColor(100, 100, 100, 100));
        // Draw slider
        sprite_batch.Draw(InfoBox_Texture, sliderRectangle, ColorSlider);
      }
      else
      {
        ArrowTime = 0;
      }
    }

    bool remove = false, sx = true;
    Vector2 rempos;
    int ind = 0;
    private void RemoveCard()
    {
      if (remove)
      {
        Animation = true;

        // Deseleziona tutte le carte sul tavolo
        cards.ForEach(c => c.card.Selected = false);

        rempos = cards.ElementAt(ind).coordPosition;

        cards.ElementAt(ind).depth = CARD_DEPTH + 0.1f;

        if (sx) cards.ElementAt(ind).coordPosition.X -= 10;
        else cards.ElementAt(ind).coordPosition.X += 10;

        if (Tutorial) DrawMessage(Locale.Strings.TutorialHint05, font1, new Vector2(cards.ElementAt(ind-1).coordPosition.X + CARD_WIDTH + position, 250));

        if (rempos.X < cards[ind - 1].coordPosition.X || rempos.X > cards[ind + 1].coordPosition.X)
        {
          // Aggiorna Mazzetti
          if (sx) mazzetto[ind - 1] += mazzetto[ind];
          else mazzetto[ind + 1] += mazzetto[ind];
          for (int i = ind; i < mazzetto.Length - 1; i++)
            mazzetto[i] = mazzetto[i + 1];

          remove = false;
          Animation = false;

          // Aggiorna Carte
          UpdateCards();
        }
      }
    }

    private void DrawMazzetti()
    {
      for (int i = 0; i < cards.Count; i++)
      {
        float depth = (0.01f) / mazzetto[i];

        for (int y = 1; y < mazzetto[i] && y < 10; y++)
        {
          if (cards[i].card.Selected) sprite_batch.Draw(Card_Texture, new Rectangle((int)cards[i].coordPosition.X - y, (int)cards[i].coordPosition.Y + y - yMove, CARD_WIDTH, CARD_HEIGHT), null, XNAColor.White, 0.0f, Vector2.Zero, SpriteEffects.None, (0.1f - (depth * y)));
          else sprite_batch.Draw(Card_Texture, new Rectangle((int)cards[i].coordPosition.X - y, (int)cards[i].coordPosition.Y + y, CARD_WIDTH, CARD_HEIGHT), null, XNAColor.White, 0.0f, Vector2.Zero, SpriteEffects.None, (0.1f - (depth * y)));

          if (Hints) //sprite_batch.DrawString(font1, mazzetto[i].ToString(), new Vector2((int)cards[i].coordPosition.X + 30, (int)cards[i].coordPosition.Y - 30), XNAColor.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
            DrawMessage(mazzetto[i].ToString(), font1, new Vector2((int)cards[i].coordPosition.X + 35 + position, 250));
        }
      }
    }

    int Noise = 0;
    /// <summary>
    /// Disegna In primo piano un Messaggio informativo
    /// </summary>
    /// <param name="mess">Messaggio</param>
    /// <param name="fnt">SpriteFont da utillizzare</param>
    /// <param name="pos">Posizione del Messaggio</param>
    private void DrawMessage(String mess, SpriteFont fnt, Vector2 pos)
    {
      Vector2 messDim = fnt.MeasureString(mess);
      Rectangle messageBox = new Rectangle((int)pos.X - position, (int)pos.Y, (int)messDim.X + 15, (int)messDim.Y + 15);

      sprite_batch.Draw(InfoBox_Texture, messageBox, new Rectangle(0, 0, InfoBox_Texture.Width, InfoBox_Texture.Height), new XNAColor(200, 200, 200, 200), 0.0f, Vector2.Zero, SpriteEffects.None, 0.999f);
      sprite_batch.DrawString(font1, mess, new Vector2((int)pos.X + 10 - position, (int)pos.Y + 10), XNAColor.Black, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
    }

    float tutorialTime;
    /// <summary>
    /// Disegna i Messaggi del Tutorial
    /// </summary>
    private void DrawTutorial(GameTime gameTime)
    {
      string PlayerName = "";

      //DrawMessage(tutorialTime.ToString(), font1, new Vector2(600, 300));

      if (board_service.Players.ElementAt(0).Name != "default") PlayerName = " " + board_service.Players.ElementAt(0).Name;
      else PlayerName = "";

      if (tutorialTime > 0 && tutorialTime < 3) DrawMessage(String.Format(Locale.Strings.Hello, PlayerName), font1, new Vector2(200, 310));
      if (tutorialTime > 5 && tutorialTime < 10) DrawMessage(Locale.Strings.TutorialWelcome01.Replace("\\n", "\n"), font1, new Vector2(200, 310));

      if (tutorialTime > 15 && tutorialTime < 20) tutorialTime = 15; // Pausa (Attesa che venga selezionata un carta)

      if (tutorialTime > 10 && tutorialTime <= 15) DrawMessage(Locale.Strings.TutorialWelcome02, font1, new Vector2(200, 310));

      if (tutorialTime > 25 && tutorialTime < 30) DrawMessage(Locale.Strings.TutorialWelcome03.Replace("\\n", "\n"), font1, new Vector2(200, 310));
      
      if (tutorialTime > 35 && tutorialTime < 40) DrawMessage(Locale.Strings.TutorialWelcome04.Replace("\\n", "\n"), font1, new Vector2(200, 310));
    }

    private int OutroTime = 0; // Idicatore di Step
    private CardState c1, c2, c3, c4, c5, c6; // Ausiliarie
    /// <summary>
    /// Disegna Animazione d'Uscita
    /// </summary>
    public void DrawOutro()
    {
      // Step 1 - Attendi che le Animazioni siano finite
      if (!Animation && !extractCard) OutroTime++;

      // Step 2 - Disattiva sistemi
      if (OutroTime == 1)
      {
        Animation = true;
        Input = false;
        //position = 0;
        scrolling = false;
        extractCard = false;
        remove = false;
        Hints = false;
        Tutorial = false;

        OutroTime++;
      }

      // Step 3 - Scorre fino all'inizio del tavolo 
      if (OutroTime == 2)
      {
        position += (Math.Abs(position) + 10) / 10;
        if (position >= 1) { position = 0; OutroTime++; }
      }

      // Step 4 - Calcola primi 6 Mazzetti per il punteggio
      if (OutroTime == 3)
      {
        UpdateCards();
        int CardsCount = cards.Count();

        c1 = cards[0];
        c2 = cards[1];
        if (CardsCount > 2) c3 = cards[2];
        if (CardsCount > 3) c4 = cards[3];
        if (CardsCount > 4) c5 = cards[4];
        if (CardsCount > 5) c6 = cards[5];

        cards.Clear();

        cards.Add(c1);
        cards.Add(c2);
        if (CardsCount > 2) cards.Add(c3);
        if (CardsCount > 3) cards.Add(c4);
        if (CardsCount > 4) cards.Add(c5);
        if (CardsCount > 5) cards.Add(c6);

        OnExit();

        OutroTime++;
      }

      // Step 5 - Oscura lo schermo e solleva le carte
      if (OutroTime > 3)
      {
        if (color_Background.R > 0) color_Background.R -= 3;
        if (color_Background.G > 0) color_Background.G -= 3;
        if (color_Background.B > 0) color_Background.B -= 3;

        if (color_Background.A > 0) color_Background.A -= (byte)3;

        for (int j = 0; j < cards.Count; j++)
          if (cards[j].coordPosition.Y > 20) cards[j].coordPosition.Y -= 2;
      }
    }

    public event ClickPlayerCard ClickPlayerCard;
    public event ClickBlockCard ClickBlockCard;
    public event ClickPack ClickPack;
    public event ReleasePlayerCard ReleasePlayerCard;
    public event OnExit OnExit;
  }
}
